package com.apes.fico.finance.service;

import com.apes.fico.finance.model.statements.BalanceSheet;
import com.apes.fico.finance.model.statements.BalanceSheetFormula;
import com.apes.fico.finance.respository.*;
import com.apes.fico.masterdata.gl.model.AccountingPeriodItem;
import com.apes.fico.masterdata.gl.respository.AccountingPeriodItemRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.MapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName BalanceSheetService
 * @Description TODO
 * @Author pengyb
 * @Date 2019/2/25 13:54
 * @Version 1.0
 **/
@Service("balanceSheetService")
public class BalanceSheetService extends DomainService {
    @Autowired
    private BalanceSheetRepository balanceSheetRepository;
    @Autowired
    private ChartAuxRepository chartAuxRepository;
    @Autowired
    private AccountingPeriodItemRepository accountingPeriodItemRepository;

    public static final String ENDING_BALANCE = "endingBalance";   //期末余额
    public static final String OPENING_BALANCE = "openingBalance"; //年初余额
    public static final String LIABILITY_ENDING_BALANCE = "liabilityEndingBalance";//负债期末余额
    public static final String LIABILITY_OPENING_BALANCE = "liabilityOpeningBalance";// 负债年初余额

    /**
     * 查询资产负债表
     *
     * @param request
     * @return
     */
    public List<Map> findAll(SimpleRequest request) {
        String company = request.get("company");
        int month = request.get("month");
        int year = request.get("year");
        AccountingPeriodItem accountingPeriodItem = accountingPeriodItemRepository.findByCompanyAndMonthAndYear(company, month, year);
        if (accountingPeriodItem == null) throw new RuntimeException("无会计记录公司");
        int period = accountingPeriodItem.getYearMonth();

        List<Map> maps = new ArrayList<>();
        List<Map> balance = balanceSheetRepository.findBalance();

        for (int i = 0; i < balance.size(); i++) {
            Map balanceSheet = balance.get(i);
            Map map = new HashMap();
            map.put("id", balanceSheet.get("ID"));
            map.put("assSeq", balanceSheet.get("ASS_SEQ"));
            map.put("ass", balanceSheet.get("ASS"));
            map.put("liabilityEquitySeq", balanceSheet.get("LIABILITY_EQUITY_SEQ"));
            map.put("liabilityEquity", balanceSheet.get("LIABILITY_EQUITY"));
            map.put("liabilityEquation", balanceSheet.get("LIABILITY_EQUATION"));
            map.put("assEquation", balanceSheet.get("ASS_EQUATION"));
            map.put(ENDING_BALANCE, 0);
            map.put(OPENING_BALANCE, 0);
            map.put(LIABILITY_ENDING_BALANCE, 0);
            map.put(LIABILITY_OPENING_BALANCE, 0);
            if (Objects.nonNull(balanceSheet.get("ASSCHART"))){
                map.put("assChart", balanceSheet.get("ASSCHART"));
            }
            if (Objects.nonNull(balanceSheet.get("LIABILITYEQUITYCHART"))){
                map.put("liabilityEquityChart", balanceSheet.get("LIABILITYEQUITYCHART"));
            }
            maps.add(map);
        };

        List<Map> chartAmouts = chartAuxRepository.findAllByCompanyAndPeriodAndYearGroup(company, period, year);
        List<Map> initMaps = chartAuxRepository.findAllByCompanyAndPeriodAndYearInit(company, year);

        //科目发生额
        Map<String, Map> chartMap = new HashMap<>();
        chartAmouts.stream().forEach(item -> {
            chartMap.put((String) item.get("CODE"), MapUtil.mapper(
                   "endingBalance" ,item.get("ENDINGBALANCE"),
                   "openingBalance" ,item.get("OPENING_BALANCE")
            ));
        });

        //年初余额数
        Map<String, Map> initMap = new HashMap<>();
        initMaps.stream().forEach(item -> {
            initMap.put((String) item.get("CODE"), MapUtil.mapper(
                    "openingBalance" ,item.get("OPENING_BALANCE")
            ));
        });

        //资产与负债
        Map<String, Map> mapMap = new HashMap<>();
        for (int i = 0; i < maps.size(); i++) {

            Map getbearingsMap = new HashMap();
            getbearingsMap.put(ENDING_BALANCE, 0);
            getbearingsMap.put(OPENING_BALANCE, 0);
            getbearingsMap.put(LIABILITY_ENDING_BALANCE, 0);
            getbearingsMap.put(LIABILITY_OPENING_BALANCE, 0);

            if (maps.get(i).containsKey("assChart")) {
                Map map = split(maps.get(i).get("assChart").toString(), chartMap, initMap);
                maps.get(i).put(ENDING_BALANCE, map.get(ENDING_BALANCE));
                maps.get(i).put(OPENING_BALANCE, map.get(OPENING_BALANCE));

                //将数据再放入map中，方便后续运算
                getbearingsMap.put(ENDING_BALANCE, maps.get(i).get(ENDING_BALANCE));
                getbearingsMap.put(OPENING_BALANCE, maps.get(i).get(OPENING_BALANCE));
            }
            if (maps.get(i).containsKey("liabilityEquityChart")) {
                Map map = split(maps.get(i).get("liabilityEquityChart").toString(), chartMap, initMap);
                maps.get(i).put(LIABILITY_ENDING_BALANCE, map.get(ENDING_BALANCE));
                maps.get(i).put(LIABILITY_OPENING_BALANCE, map.get(OPENING_BALANCE));

                //将数据再放入map中，方便后续运算
                getbearingsMap.put(LIABILITY_ENDING_BALANCE, maps.get(i).get(LIABILITY_ENDING_BALANCE));
                getbearingsMap.put(LIABILITY_OPENING_BALANCE, maps.get(i).get(LIABILITY_OPENING_BALANCE));
            }
            //将数据再放入map中，方便后续运算
            mapMap.put(maps.get(i).get("id").toString(), getbearingsMap);
        }
        maps = maps.stream().sorted(Comparator.comparing(map -> Integer.parseInt(map.get("id").toString()))).collect(Collectors.toList());
        //公式
        for (int i = 0; i < maps.size(); i++) {
            if (maps.get(i).containsKey("assEquation") && maps.get(i).get("assEquation") != null) {
                Map map = equation(maps.get(i).get("assEquation").toString(), ENDING_BALANCE, OPENING_BALANCE, mapMap);
                maps.get(i).put(ENDING_BALANCE, map.get("endingAmount"));
                maps.get(i).put(OPENING_BALANCE, map.get("openingAmount"));

                mapMap.put(maps.get(i).get("id").toString(), maps.get(i));
            }
            if (maps.get(i).containsKey("liabilityEquation") && maps.get(i).get("liabilityEquation") != null) {
                Map map = equation(maps.get(i).get("liabilityEquation").toString(), LIABILITY_ENDING_BALANCE, LIABILITY_OPENING_BALANCE, mapMap);
                maps.get(i).put(LIABILITY_ENDING_BALANCE, map.get("endingAmount"));
                maps.get(i).put(LIABILITY_OPENING_BALANCE, map.get("openingAmount"));

                mapMap.put(maps.get(i).get("id").toString(), maps.get(i));
            }
        }

        return maps;
    }

    /**
     * 字符分割后求值
     *
     * @param str
     * @param map
     * @return
     */
    private Map split(String str, Map<String, Map> map, Map<String, Map> initMap) {
        Map<String, Map> chartMap = new HashMap<>();
        Map<String, Map> chartInitMap = new HashMap<>();
        double openingBalance = 0;
        double endingBalance = 0;
        String regex = "\\$";
        String[] strs = str.split(regex);

        for (int i = 0; i < strs.length; i++) {
            String codeStr = strs[i];
            String[] codeStrs = codeStr.split("#");
            String code = codeStrs[1];
            String orientation = codeStrs[0]; //运算符
            chartMap = getLikeByMap(map, code);
            chartInitMap = getLikeByMap(initMap, code);
            if (chartMap.size() != 0) {
                double value = getValueByMap(chartMap,ENDING_BALANCE);
                if (orientation.equals("-")) {
                    //期末余额
                    endingBalance += value * -1.0;
                } else {
                    //期末余额
                    endingBalance += value;
                }
            }
            if (initMap.size() != 0) {
                double value = getValueByMap(chartInitMap,OPENING_BALANCE);
                if (orientation.equals("-")) {
                    //期初余额
                    openingBalance += value * -1.0;
                } else {
                    //期初余额
                    openingBalance += value;
                }
            }
        }
        Map resultMap = new HashMap();
        resultMap.put(OPENING_BALANCE, openingBalance);
        resultMap.put(ENDING_BALANCE, endingBalance);
        return resultMap;
    }


    /**
     * 公式计算
     *
     * @param str
     * @param ending
     * @param opening
     * @return
     */
    private Map equation(String str, String ending, String opening, Map<String, Map> mapMap) {
        Map arrayMap = equationSplit(str);
        String[] strs1 = (String[]) arrayMap.get("strs1");//去符号数组
        String[] strs2 = (String[]) arrayMap.get("strs2");//去数字数组

        double endingAmount = 0;
        double openingAmount = 0;
        for (int i = 0; i < strs1.length; i++) {
            String equationSeq = strs1[i];
            Map map = mapMap.get(equationSeq);//行次唯一
            double endingBalance = Double.parseDouble(String.valueOf(map.get(ending)));
            double openingBalance = Double.parseDouble(String.valueOf(map.get(opening)));


            if (i == 0) {
                endingAmount += endingBalance;
                openingAmount += openingBalance;
            } else {
                if (strs2[i - 1].equals("+")) {
                    endingAmount += endingBalance;
                    openingAmount += openingBalance;
                } else {
                    endingAmount = endingAmount - endingBalance;
                    openingAmount = openingAmount - openingBalance;
                }
            }
        }
        Map map = new HashMap();
        map.put("endingAmount", endingAmount);
        map.put("openingAmount", openingAmount);
        return map;
    }

    /**
     * 获得资产与负债
     *
     * @param balanceSheetsMap
     * @param balanceSheetFormulaMap
     * @return
     */
    private List<Map> fun(Map<String, BalanceSheet> balanceSheetsMap, Map<String, BalanceSheetFormula> balanceSheetFormulaMap) {
        List<Map> maps = new ArrayList<>();
        Map<String, Map> mapMap = new HashMap<>();
        for (Map.Entry<String, BalanceSheetFormula> balanceSheetFormula : balanceSheetFormulaMap.entrySet()) {
            Map<String, String> map = new HashMap<>();
            if (mapMap.containsKey(balanceSheetFormula.getValue().getSeq())) {
                map.put("code", mapMap.get(balanceSheetFormula.getValue().getSeq()).get("code") + "$" + balanceSheetFormula.getValue().getOrientation() + "$" + balanceSheetFormula.getValue().getCode());
            } else {
                map.put("seq", balanceSheetFormula.getValue().getSeq());
                map.put("code", balanceSheetFormula.getValue().getOrientation() + "$" + balanceSheetFormula.getValue().getCode());
            }
            mapMap.put(map.get("seq"), map);

        }
        for (Map.Entry<String, BalanceSheet> balanceSheet : balanceSheetsMap.entrySet()) {
            Map map = new HashMap();
            map.put("id", balanceSheet.getValue().getId());
            map.put("assSeq", balanceSheet.getValue().getAssSeq());
            map.put("ass", balanceSheet.getValue().getAss());
            map.put("liabilityEquitySeq", balanceSheet.getValue().getLiabilityEquitySeq());
            map.put("liabilityEquity", balanceSheet.getValue().getLiabilityEquity());
            map.put("assEquation", balanceSheet.getValue().getAssEquation());
            map.put("liabilityEquation", balanceSheet.getValue().getLiabilityEquation());
            map.put(ENDING_BALANCE, 0);
            map.put(OPENING_BALANCE, 0);
            map.put(LIABILITY_ENDING_BALANCE, 0);
            map.put(LIABILITY_OPENING_BALANCE, 0);
            if (mapMap.containsKey(balanceSheet.getValue().getAssSeq())) {
                map.put("assChart", mapMap.get(balanceSheet.getValue().getAssSeq()).get("code"));
            }
            if (mapMap.containsKey(balanceSheet.getValue().getLiabilityEquitySeq())) {
                map.put("liabilityEquityChart", mapMap.get(balanceSheet.getValue().getLiabilityEquitySeq()).get("code"));
            }

            maps.add(map);
        }


        return maps;
    }


    /**
     * 分割公式
     *
     * @param str
     * @return
     */
    public Map equationSplit(String str) {
        String regex = "[A-Za-z]";
        String regexNumber = "[0-9]";
        String regexTwo = "[\\+\\-]";
        String str1 = str.replaceAll(regex, "");//去字母
        String[] strs1 = str1.split(regexTwo);//去符号数组
        String[] strs2 = removeempty(str1.split(regexNumber));//去数字数组
        Map<String, String[]> map = new HashMap<>();
        map.put("strs1", strs1);
        map.put("strs2", strs2);
        return map;
    }


    /**
     * 字符数组去空格
     *
     * @param strs
     * @return
     */
    private String[] removeempty(String[] strs) {
        List<String> tmp = new ArrayList<String>();
        for (String str : strs) {
            if (str != null && str.length() != 0) {
                tmp.add(str);
            }
        }
        strs = tmp.toArray(new String[0]);
        return strs;
    }


    /**
     * 自定义Map集合key头部模糊匹配
     *
     * @param map
     * @param keyLike
     * @return
     */
    public static Map getLikeByMap(Map<String, Map> map, String keyLike) {
        Map<String, Map> chartMap = new HashMap<>();
        for (Map.Entry<String, Map> entity : map.entrySet()) {
            if (entity.getKey().substring(0, keyLike.length()).equals(keyLike)) {
                chartMap.put(entity.getKey(), entity.getValue());
            }
        }
        return chartMap;
    }

    /**
     * 自定义Map的value求值（期末余额）
     *
     * @param map
     * @return
     */
    public static double getValueByMap(Map<String, Map> map,String field) {
        double endingBalance = 0;
        for (Map.Entry<String, Map> entry : map.entrySet()) {
            endingBalance += Double.parseDouble(String.valueOf(entry.getValue().get(field)));
        }
        return endingBalance;
    }


}
